Аналитики в Яндекс.Дзене занимаются анализом пользовательского взаимодействия с карточками статей. Каждую карточку определяют её тема и источник (у него тоже есть тема). Пользователей системы характеризует возрастная категория. Есть три способа взаимодействия пользователей с системой:
Каждую неделю необходимо ответить на одни и те же вопросы:
Цель проекта - анализ взаимодействия пользователей с карточками Яндекс.Дзен.
Для этого необходимо:
# импортируем библиотеки
import pandas as pd
from sqlalchemy import create_engine
from datetime import datetime
import plotly
from plotly import graph_objects as go
import plotly.figure_factory as ff
import plotly.io as pio
pio.templates.default = 'seaborn'
# %%HTML
# <style type="text/css">
# table.dataframe td, table.dataframe th {
# border: 1px black solid !important;
# color: black !important;
# }
# создадим коннекцию к базе
# db_config = {'user' : 'praktikum_student', # имя пользователя
# 'pwd' : 'Sdf4$2;d-d30pp', # пароль
# 'host' : 'rc1b-wcoijxj3yxfsf3fs.mdb.yandexcloud.net',
# 'port' : 6432, # порт подключения
# 'db' : 'data-analyst-zen-project-db'} # название базы данных
# connection_string = 'postgresql://{}:{}@{}:{}/{}'.format(db_config['user'],
# db_config['pwd'],
# db_config['host'],
# db_config['port'],
# db_config['db'])
# engine = create_engine(connection_string)
# выполним sql-запрос
# query = '''
# SELECT *
# FROM dash_visits
# '''
# dash_visits = pd.io.sql.read_sql(query, con = engine)
# dash_visits.head()
# сохраним выгруженную таблицу в формате "csv"
# dash_visits.to_csv('dash_visits.csv', index=False)
dash_visits = pd.read_csv('dash_visits.csv')
dash_visits.head()
# посмотрим сводную информацию таблицы
dash_visits.info()
В таблице 30745 строк, 6 столбцов, тип данных у четырех столбцов строковый, у двух - целочисленный. В столбце dt значения даты и времени взаимодействия необходимо привести к формату datetime.
# посмотрим на уникальные значения по столбцам таблицы
for column in dash_visits.columns:
if (dash_visits[column].dtype == 'object'):
print(column)
print()
print(dash_visits[column].unique())
print('Количество уникальных значений',
dash_visits[column].nunique())
print()
print()
Всего 25 уникальных значений тем карточек, 26 - тем источников, пользователи распределены на 6 возрастных групп. Имеется информация за 24 сентября 2019 года, период с 18 часов 28 минут по 19 часов, при этом данные с 18 часов 36 минут по 18 часов 51 минуту отсутствуют.
# посмотрим статистичускую информацию количества взаимодействий пользователей с системой
dash_visits['visits'].describe()
Минимальное количество взаимодействий с группировкой по темам карточек, темам источников и возрастным группам - 1, максимальное - 371, среднее арифметическое - 10, медиана - 3.
# приведем значения даты и времени взаимодействия к формату `datetime`
dash_visits['dt'] = pd.to_datetime(dash_visits['dt'])
dash_visits['dt'].unique()
# для удобства визуализации преобразуем значения даты и времени взаимодействия
dash_visits['dt'] = dash_visits['dt'].apply(lambda x: x.strftime('%H-%M'))
dash_visits['dt'].unique()
# определим количество пропущенных значений в таблице
dash_visits.isnull().sum()
# посчитаем количество дубликатов
dash_visits.duplicated().sum()
Пропущенные значения и дубликаты отсутствуют.
В целях выгрузки данных:
При изучении таблицы с данными установлено:
dt значения даты и времени взаимодействия необходимо привести к формату datetime; Для подготовки данных:
dt значения даты и времени взаимодействия привели к формату datetime; dt для удобства визуализации преобразовали значения даты и времени взаимодействия.В Tableau Public сформируем дашборд в соответствии с приведенным макетом.

По ссылке дашборд опубликован в открытом доступе.
Учитывая, что в Tableau Public невозможно сохранить построенные графики, проведем анализ данных для подготовки презентации в Jupyter Notebook.
# посчитаем общее количество взаимодействий пользователей
dash_visits['visits'].sum()
Всего пользователями осуществлено 310207 взаимодействий.
# создадим таблицу с количеством взаимодействий пользователей по времени
visits_time = dash_visits.groupby('dt')\
.agg(visits_count = ('visits', 'sum'))\
.reset_index()
visits_time
# построим график количества взаимодействий пользователей по времени
fig = go.Figure()
fig.add_trace(go.Scatter(x = visits_time['dt'],
y = visits_time['visits_count'],
mode = 'lines + markers + text',
text = visits_time['visits_count'],
textposition = 'top center',
textfont = dict(family = 'sans serif', size = 18, color = 'crimson'),
line = dict(color = 'royalblue', width = 4),
marker = dict(color = 'royalblue', size = 10)))
fig.update_layout(yaxis = dict(range = [-1000, 66000]),
title = 'Количество взаимодействий пользователей по времени',
title_font = dict(family = 'sans serif', size = 20),
xaxis_title = 'Время',
yaxis_title = 'Количество взаимодействий',
showlegend = False,
margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.add_annotation(x = '18-35', y = 6000,
text='С 18-36 до 18-51 данные отсутствуют',
showarrow = True,
arrowhead = 1,
arrowsize = 1,
arrowwidth = 2,
arrowcolor = 'black',
font = dict(family = 'sans serif', size = 14, color = 'white'),
align = 'center',
bordercolor = 'royalblue',
borderwidth = 2,
borderpad = 4,
bgcolor = 'crimson',
opacity = 0.8)
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Время: %{x}<br>Взаимодействий: %{y}')
fig.show()
Максимальное количество взаимодействий осуществлено пользователями с 18 часов 56 минут по 18 часов 59 минут.
# создадим таблицу с количеством взаимодействий пользователей по темам карточек
item_visits = dash_visits.groupby('item_topic')\
.agg(visits_count = ('visits', 'sum'))\
.sort_values(by = 'visits_count', ascending = False)\
.reset_index()
item_visits.head(10)
Более 15000 взаимодействий осуществлено по 8 темам карточек.
# построим график количества взаимодействий пользователей по темам карточек
fig = go.Figure()
colors = ['royalblue',] * 26
colors[0:9] = ['midnightblue',] * 8
fig.add_trace(go.Bar(x = item_visits['item_topic'],
y = item_visits['visits_count'],
marker_color = colors,
text = item_visits['visits_count'],
textposition = 'outside',
textfont = dict(family = 'sans serif', size = 11, color = 'crimson')))
fig.update_layout(title = 'Количество взаимодействий пользователей по темам карточек',
title_font = dict(family = 'sans serif', size = 20),
xaxis_title = 'Тема карточек',
yaxis_title = 'Количество взаимодействий',
showlegend = False,
margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Тема: %{x}<br>Взаимодействий: %{y}')
fig.show()
Наибольшее количество взаимодействий по карточкам с темами "Наука", "Отношения", "Интересные факты" и "Общество".
# создадим таблицу с количеством взаимодействий пользователей по темам источников
source_visits = dash_visits.groupby('source_topic')\
.agg(visits_count = ('visits', 'sum'))\
.sort_values(by = 'visits_count', ascending = False)\
.reset_index()
source_visits.head(10)
Более 20000 взаимодействий осуществлено из источников по 6 темам.
# построим график количества взаимодействий пользователей по темам источников
fig = go.Figure()
colors = ['royalblue',] * 27
colors[0:7] = ['midnightblue',] * 6
fig.add_trace(go.Bar(x = source_visits['source_topic'],
y = source_visits['visits_count'],
marker_color = colors,
text = source_visits['visits_count'],
textposition = 'outside',
textfont = dict(family = 'sans serif', size = 11, color = 'crimson')))
fig.update_layout(title = 'Количество взаимодействий пользователей по темам источников',
title_font = dict(family = 'sans serif', size = 20),
xaxis_title = 'Тема источников',
yaxis_title = 'Количество взаимодействий',
showlegend = False,
margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Тема: %{x}<br>Взаимодействий: %{y}')
fig.show()
Наибольшее количество взаимодействий у источников с темами "Семейные отношения", "Россия" и "Полезные советы".
# создадим таблицу с количеством взаимодействий пользователей по возрастным группам
age_visits = dash_visits.groupby('age_segment')\
.agg(visits_count = ('visits', 'sum'))\
.sort_values(by = 'visits_count', ascending = False)\
.reset_index()
age_visits
# построим график количества взаимодействий пользователей по возрастным группам
fig = go.Figure()
colors = ['royalblue',] * 6
colors[0] = 'midnightblue'
fig.add_trace(go.Bar(x = age_visits['age_segment'],
y = age_visits['visits_count'],
marker_color = colors,
text = age_visits['visits_count'],
textposition = 'outside',
textfont = dict(family = 'sans serif', size = 16, color = 'crimson')))
fig.update_layout(title = 'Количество взаимодействий пользователей по возрастным группам',
title_font = dict(family = 'sans serif', size = 20),
xaxis_title = 'Возрастная группа',
yaxis_title = 'Количество взаимодействий',
showlegend = False,
margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Возрастная группа: %{x}<br>Взаимодействий: %{y}')
fig.show()
Наибольшее количество взаимодействий у возрастной группы от 18 до 25 лет.
# создадим таблицу с количеством взаимодействий пользователей по темам карточек и времени
item_visits_time = dash_visits.groupby(['dt', 'item_topic'])\
.agg(visits_count = ('visits', 'sum'))\
.reset_index()
item_visits_time.head()
# построим график количества взаимодействий пользователей по темам карточек и времени с абсолютными значениями
fig = go.Figure()
for item in item_visits_time['item_topic'].unique():
fig.add_trace(go.Scatter(x = item_visits_time.query('item_topic == @item')['dt'],
y = item_visits_time.query('item_topic == @item')['visits_count'],
mode = 'lines',
name = item,
stackgroup = 'one'))
fig.update_layout(yaxis = dict(range = [7, 65000]),
title = 'Количество взаимодействий пользователей по темам карточек и времени (абсолютные значения)',
title_font = dict(family = 'sans serif', size = 20),
xaxis_title = 'Время',
yaxis_title = 'Количество взаимодействий',
showlegend = False,
margin = dict(l = 0, r = 20, t = 70, b = 0))
def annotation(y, text):
fig.add_annotation(x = '18-57',
y = y,
text = ' ' + text,
showarrow = False)
annotation_dict = {26000 : 'Наука',
34000 : 'Отношения',
13000 : 'Интересные факты',
30000 : 'Общество',
38000 : 'Подборки',
50000 : 'Россия',
41000 : 'Полезные советы',
19000 : 'История'}
for k, v in annotation_dict.items():
annotation(k, v)
fig.add_annotation(x = '18-35', y = 4000,
text='С 18-36 до 18-51 данные отсутствуют',
showarrow = True,
arrowhead = 1,
arrowsize = 1,
arrowwidth = 2,
arrowcolor = 'black',
font = dict(family = 'sans serif', size = 14, color = 'white'),
align = 'center',
bordercolor = 'royalblue',
borderwidth = 2,
borderpad = 4,
bgcolor = 'crimson',
opacity = 0.8)
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Время: %{x}<br>Взаимодействий: %{y}')
fig.show()
В период 18 часов 57 минут и 18 часов 58 минут наблюдалось максимальное количество взаимодействий пользователей по всем темам карточек.
# построим график количества взаимодействий пользователей по темам карточек и времени с относительными значениями
fig = go.Figure()
for item in item_visits_time['item_topic'].unique():
fig.add_trace(go.Scatter(x = item_visits_time.query('item_topic == @item')['dt'],
y = item_visits_time.query('item_topic == @item')['visits_count'],
mode = 'lines',
name = item,
stackgroup = 'one',
groupnorm = 'percent'))
fig.update_layout(yaxis = dict(range = [1, 102]),
title = 'Количество взаимодействий пользователей по темам карточек и времени (относительные значения)',
title_font = dict(family = 'sans serif', size = 20),
xaxis_title = 'Время',
yaxis_title = 'Процент взаимодействий',
showlegend = False,
margin = dict(l = 0, r = 20, t = 70, b = 0))
def annotation(y, text):
fig.add_annotation(x = '18-55',
y = y,
text = text,
showarrow = False)
annotation_dict = {43 : 'Наука',
56 : 'Отношения',
22 : 'Интересные факты',
49 : 'Общество',
62 : 'Подборки',
82 : 'Россия',
68 : 'Полезные советы',
30 : 'История'}
for k, v in annotation_dict.items():
annotation(k, v)
fig.add_annotation(x = '18-35', y = 5,
text='С 18-36 до 18-51 данные отсутствуют',
showarrow = True,
arrowhead = 1,
arrowsize = 1,
arrowwidth = 2,
arrowcolor = 'black',
font = dict(family = 'sans serif', size = 14, color = 'white'),
align = 'center',
bordercolor = 'royalblue',
borderwidth = 2,
borderpad = 4,
bgcolor = 'crimson',
opacity = 0.8)
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Время: %{x}<br>Процент: %{y}')
fig.show()
Доля взаимодействий пользователей по темам карточек со временем практически не меняется.
# создадим таблицу с количеством взаимодействий пользователей по темам карточек и возрастным группам
item_age_visits = dash_visits.pivot_table(index = 'item_topic',
columns = 'age_segment',
values = 'visits',
aggfunc = 'sum')
item_age_visits.head()
# построим график количества взаимодействий пользователей по темам карточек и возрастным группам
fig = go.Figure()
x = item_age_visits.columns.to_list()
y = item_age_visits.index.to_list()
z = item_age_visits.values
fig = ff.create_annotated_heatmap(z, x = x, y = y, colorscale = 'ice')
fig.update_layout(title = 'Количество взаимодействий пользователей по темам карточек и возрастным группам',
title_font = dict(family = 'sans serif', size = 20),
margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.update_traces(hovertemplate = 'Возрастная группа: %{x}<br>Тема карточек: %{y}<br>Взаимодействий: %{z}')
for i in range(len(fig.layout.annotations)):
fig.layout.annotations[i].font.size = 11
fig.show()
У пользователей возрастной группы с 18 до 25 лет наибольшее количество взаимодействий на темы "Отношения", "Наука", "Общество" и "Интересные факты", у других возрастных групп предпочтения такие же, но наиболее популярными являются темы "Наука" и "Интересные факты".
# создадим таблицу с количеством взаимодействий пользователей по темам карточек и темам источников
item_source_visits = dash_visits.pivot_table(index = 'item_topic',
columns = 'source_topic',
values = 'visits',
aggfunc = 'sum')
item_source_visits = item_source_visits.fillna(0)
item_source_visits = item_source_visits.astype('int')
item_source_visits.head()
# построим график количества взаимодействий пользователей по темам карточек и темам источников
fig = go.Figure()
x = item_source_visits.columns.to_list()
y = item_source_visits.index.to_list()
z = item_source_visits.values
fig = ff.create_annotated_heatmap(z, x = x, y = y, colorscale = 'ice')
fig.update_layout(title = 'Количество взаимодействий пользователей по темам карточек и темам источников',
title_font = dict(family = 'sans serif', size = 20),
margin = dict(l = 0, r = 20, t = 170, b = 0))
fig.update_traces(hovertemplate = 'Тема источников: %{x}<br>Тема карточек: %{y}<br>Взаимодействий: %{z}')
for i in range(len(fig.layout.annotations)):
fig.layout.annotations[i].font.size = 10
fig.show()
Наибольшее количество взаимодействий пользователей у карточек с темой "Рассказы" из источника "Путешествия", с темой "Общество" из источника "Россия" и с темой "Наука" из источника "Кино".
Всего пользователями осуществлено 310207 взаимодействий, более 15000 взаимодействий осуществлено по 8 темам карточек, более 20000 - из источников по 6 темам.
Максимальное количество взаимодействий осуществлено пользователями с 18 часов 56 минут по 18 часов 59 минут, по карточкам с темами "Наука", "Отношения", "Интересные факты" и "Общество", из источников с темами "Семейные отношения", "Россия" и "Полезные советы", возрастной группы от 18 до 25 лет.
В период 18 часов 57 минут и 18 часов 58 минут наблюдалось максимальное количество взаимодействий пользователей по всем темам карточек, при этом доля взаимодействий пользователей по темам карточек со временем практически не меняется.
У пользователей возрастной группы с 18 до 25 лет наибольшее количество взаимодействий на темы "Отношения", "Наука", "Общество" и "Интересные факты", у других возрастных групп предпочтения такие же, но наиболее популярными являются темы "Наука" и "Интересные факты".
Наибольшее количество взаимодействий пользователей по карточкам с темами "Рассказы" из источника "Путешествия", с темами "Общество" из источника "Россия" и с темами "Наука" из источника "Кино".
По ссылке презентация опубликована в открытом доступе.